package com.huanzhidadi.redis.seckill;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 商品秒杀 用Redis与Lua预防库存超卖
 * 手动在redis中新增一个key为goods:1001，value为10的键
 * 然后启动服务
 * 最后执行SeckillController的main方法进行测试
 */
@RestController
public class SeckillController {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/seckill")
    public String seckill() {
        String goodsKey = "goods:1001";
        String userKey = "user:1001";
        int userId = new Random().nextInt(1000);
        ValueOperations ops = redisTemplate.opsForValue();
        ListOperations listOperations = redisTemplate.opsForList();
        Object o = ops.get("goods:1001");
        if (Integer.parseInt(ops.get(goodsKey).toString()) > 0) {
            ops.decrement(goodsKey);
            listOperations.leftPush(userKey, String.valueOf(userId));
            System.out.println(listOperations.range(userKey, 0, -1));
            return "success";
        } else {
            return "fail";
        }
    }

    @GetMapping("/seckill_lua")
    public String seckillWithLua() {
        String goodsKey = "goods:1001";
        String userKey = "user:1001";
        int userId = new Random().nextInt(1000);

        String script = "if tonumber(redis.call('get', KEYS[1]))>0 then redis.call('decr', KEYS[1]) redis.call('lpush', KEYS[2], ARGV[1]) return 1 else return 0 end";
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Long.class);

        List<String> keyList = new ArrayList<>();
        keyList.add(goodsKey);
        keyList.add(userKey);

        Long result = (Long) redisTemplate.execute(redisScript, keyList, String.valueOf(userId));

        ValueOperations ops = redisTemplate.opsForValue();
        ListOperations listOperations = redisTemplate.opsForList();

        if (result == 1) {
            System.out.println(ops.get(goodsKey));
            System.out.println(listOperations.range(userKey, 0, -1));
            return "success";
        } else {
            return "fail";
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        OkHttpClient okHttpClient = new OkHttpClient();
        final Request request = new Request.Builder()
                // .url("http://localhost:8080/seckill")
                .url("http://localhost:8080/seckill_lua")
                .get()
                .build();

        for (int i=0; i<100; i++) {
            int idx = i;
            executorService.submit(() -> {
                try {
                    Response response = okHttpClient.newCall(request).execute();
                    System.out.println(idx + ":" + response.body().string());
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

        }

        executorService.shutdown();
    }
}
